package com.flying.pas.security.service;

import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import com.flying.common.annotation.DaoCreate;
import com.flying.common.annotation.DaoQuery;
import com.flying.common.annotation.DaoRemove;
import com.flying.common.annotation.DaoUpdate;
import com.flying.common.util.Codes;
import com.flying.framework.annotation.MethodInfo;
import com.flying.framework.annotation.Param;
import com.flying.framework.annotation.Service;
import com.flying.framework.context.ServiceContext;
import com.flying.framework.model.ActionResult;
import com.flying.framework.model.ModelFactory;
import com.flying.framework.model.QueryResult;
import com.flying.framework.security.Principal;
import com.flying.framework.service.AbstractService;
import com.flying.pas.security.model.Menu;
import com.flying.pas.security.model.RolePerm;
import com.flying.pas.security.model.User;

@Service(value="MenuService", desc="")
public class MenuService extends AbstractService{
	private RolePermService rps;
	
	public void setRolePermService(RolePermService s) {
		this.rps = s;
	}
        
	@MethodInfo("新增")
	@DaoCreate(entity=Menu.ENTITY_NAME)
	public Menu create(
			@Param(value=Menu.PARENT_ID, required=false,	desc="父菜单ID") Long parent_id,
			@Param(value=Menu.NAME, required=true,	desc="名称") String name,
			@Param(value=Menu.MODULE, required=false,	desc="所属模块") String module,
			@Param(value=Menu.URL, required=false,	desc="URL") String url,
			@Param(value=Menu.REMARKS, required=false,	desc="说明") String remarks,
			@Param(value=Menu.PERM_ID, required=false,	desc="权限ID") Long perm_id,
			@Param(value=Menu.SORT_ID, required=false,	desc="排序") Integer sort_id,
			@Param(value=Menu.IS_LEAF, required=false,	desc="是否叶节点") Integer is_leaf,
			@Param(value=Menu.STATUS, required=false,	desc="状态（0：不发布，1：发布）") Integer status,
			@Param(value=Menu.CREATOR, required=false,	desc="创建人") String creator,
			@Param(value=Menu.CREATE_TIME, required=false,	desc="创建时间") Date create_time
		) throws Exception {
		Principal p = ServiceContext.getContext().getPrincipal();
		return ModelFactory.create(Menu.class,
				Menu.PARENT_ID, parent_id == null?0L: parent_id,
				Menu.CREATOR, p == null?null: p.getName(),
				Menu.CREATE_TIME, new Date());
	}

	@MethodInfo("修改")
	@DaoUpdate(entity=Menu.ENTITY_NAME)
	public ActionResult update(
			@Param(value=Menu.MENU_ID, required=true,	desc="菜单ID") Long menu_id,
			@Param(value=Menu.PARENT_ID, required=false,	desc="父菜单ID") Long parent_id,
			@Param(value=Menu.NAME, required=true,	desc="名称") String name,
			@Param(value=Menu.MODULE, required=false,	desc="所属模块") String module,
			@Param(value=Menu.URL, required=false,	desc="URL") String url,
			@Param(value=Menu.REMARKS, required=false,	desc="说明") String remarks,
			@Param(value=Menu.PERM_ID, required=false,	desc="权限ID") Long perm_id,
			@Param(value=Menu.SORT_ID, required=false,	desc="排序") Integer sort_id,
			@Param(value=Menu.IS_LEAF, required=false,	desc="是否叶节点") Integer is_leaf,
			@Param(value=Menu.STATUS, required=false,	desc="状态（0：不发布，1：发布）") Integer status,
			@Param(value=Menu.UPDATOR, required=false,	desc="修改人") String updator,
			@Param(value=Menu.UPDATE_TIME, required=false,	desc="修改时间") Date update_time
		) throws Exception {
		Principal p = ServiceContext.getContext().getPrincipal();
		return ModelFactory.create(ActionResult.class,
				Menu.PARENT_ID, parent_id == null?0L: parent_id,
				Menu.UPDATOR, p == null?null: p.getName(),
				Menu.UPDATE_TIME, new Date());
	}

	@MethodInfo("删除")
	@DaoRemove(entity=Menu.ENTITY_NAME)
	public ActionResult remove(
			@Param(value=Menu.MENU_ID, required=true,	desc="菜单ID") Long menu_id
		) throws Exception {
		
		return null;
	}

	@MethodInfo("搜索")
	@DaoQuery(entity=Menu.ENTITY_NAME, pageable=true, modelClass=Menu.class)
	public QueryResult<Menu> findAll(
			@Param(value=Codes.PAGE_NUM, 	required=false, desc="分页页号，默认0") int page,
			@Param(value=Codes.PAGE_SIZE, 	required=false, desc="分页大小，默认10") int rows) throws Exception {
		return null;
	}

	@MethodInfo("搜索")
	@DaoQuery(entity=Menu.ENTITY_NAME, pageable=false, modelClass=Menu.class, osql="order by sort_id")
	protected QueryResult<Menu> _findChildren(
			@Param(value=Menu.MODULE, required=false,	desc="所属模块") String module,
			@Param(value=Menu.PARENT_ID, required=true,	desc="父菜单ID") Long parent_id) throws Exception {
		return null;
	}

	@SuppressWarnings("unchecked")
	@MethodInfo("搜索")
	public QueryResult<Menu> findChildren(
			@Param(value=Menu.MODULE, required=false,	desc="所属模块") String module,
			@Param(value=Menu.PARENT_ID, required=true,	desc="父菜单ID") Long parent_id) throws Exception {
		int is_leaf = 0;
		if(parent_id > 0) {
			Menu p = this.findById(parent_id);
			is_leaf = p.getIsLeaf() == null? 0: p.getIsLeaf().intValue();
		}
		if(is_leaf == 0) {
			return this._findChildren(module, parent_id);
		} else {
			return ModelFactory.create(QueryResult.class);
		}
	}

	@MethodInfo("查询")
	@DaoQuery(entity=Menu.ENTITY_NAME, single=true, throwsNotFoundException=false )
	public Menu findByUrl(
			@Param(value=Menu.URL, required=true,	desc="URL") String url
		) throws Exception {
		return null;
	}

	@MethodInfo("查询")
	public QueryResult<Menu> findMyMenu(
			@Param(value=Menu.PARENT_ID, required=true,	desc="父菜单ID") Long parent_id
		) throws Exception {
		Principal p = ServiceContext.getContext().getPrincipal();
		return this.findByUserId(Long.parseLong(p.getId()), parent_id);
	}

	@MethodInfo("查询")
	public QueryResult<Menu> findByUserId(
			@Param(value=User.USER_ID, required=true,	desc="用户ID") Long user_id,
			@Param(value=Menu.PARENT_ID, required=true,	desc="父菜单ID") Long parent_id
		) throws Exception {
		QueryResult<Menu> result = this.findChildren(null, parent_id);
		List<Menu> menus = result.getRows();
		List<RolePerm> perms = this.rps.findByUserId(user_id).getRows();
		Set<Long> permIds = perms.stream().map(x -> x.getPermId()).collect(Collectors.toSet());
		this._filterMenus(menus, permIds);
		return result;
	}
	
	protected void _filterMenus(List<Menu> menus, Set<Long> permIds) {
		for(Iterator<Menu> it = menus.iterator(); it.hasNext(); ) {
			Menu m = it.next();
			Long permId = m.getPermId();
			Integer isLeaf = m.getIsLeaf() != null? m.getIsLeaf(): (m.getChildren().isEmpty()?1:0);
			if(m.getStatus() == Menu.MenuStatus.PREPARING.value()) {	//not effective
				it.remove();
				continue;
			}
			if(isLeaf.intValue() == 1 && (permId == null || permId.longValue() == 0L)) {		//no auth leaf nodes
				it.remove();
				continue;
			}
			if(permId != null && !permIds.contains(permId)) {	//no access perm
				it.remove();
				continue;
			}
			if(isLeaf.intValue() == 0) {  //scan children nodes
				this._filterMenus(m.getChildren(), permIds);
				if(m.getChildren().isEmpty()) {   //empty child mid nodes
					it.remove();
					continue;
				}
			}
		}
	}

	@MethodInfo("查询")
	@DaoQuery(entity=Menu.ENTITY_NAME, single=true, throwsNotFoundException=true )
	public Menu findById(
			@Param(value=Menu.MENU_ID, required=true,	desc="菜单ID") Long menu_id
		) throws Exception {
		return null;
	}

}